package priv.dajie.tzzq;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.*;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.*;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import priv.dajie.tzzq.bot.exception.NetworkException;
import priv.dajie.tzzq.common.IpUtil;
import priv.dajie.tzzq.proxy.Proxy;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class Base {

    private CloseableHttpClient httpClient;
    protected CookieStore cookieStore;
    private HttpHost defaultProxy;
    private HttpHost[] httpHosts;
    private int proxySelect = 0;
    private Logger logger = LogManager.getLogger(this.getClass().getName());
    private static Base clientInstance = new Base();

    {
        cookieStore = new BasicCookieStore();
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36"));
        headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9"));
        httpClientBuilder.setDefaultHeaders(headers); // 设置默认header
        httpClientBuilder.setDefaultCookieStore(cookieStore); // 设置cookies
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(25000)
                .setConnectionRequestTimeout(25000).setSocketTimeout(25000)
                .build();
        httpClientBuilder.setDefaultRequestConfig(requestConfig);
        SocketConfig socketConfig = SocketConfig.custom() // 配置代理连接时间
                .setSoKeepAlive(false)
                .setSoLinger(1)
                .setSoReuseAddress(true)
                .setSoTimeout(25000)
                .setTcpNoDelay(true).build();
        httpClientBuilder.setDefaultSocketConfig(socketConfig);
        httpClientBuilder.setRedirectStrategy(new DefaultRedirectStrategy() {
            @Override
            public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException { // 网页重定向自动跳转
                boolean isRedirect = false;
                try {
                    isRedirect = super.isRedirected(request, response, context);
                } catch (ProtocolException e) {
                    e.printStackTrace();
                }
                if (!isRedirect) {
                    int responseCode = response.getStatusLine().getStatusCode();
                    if (responseCode == 301 || responseCode == 302) {
                        return true;
                    }
                }
                return isRedirect;
            }
        });
        HttpRequestRetryHandler retry = new HttpRequestRetryHandler() {
            @Override
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if (executionCount >= 3) {// 如果已经重试了3次，就放弃
                    return false;
                }
                if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接，那么就重试
                    return true;
                }
                if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常
                    return false;
                }
                if (exception instanceof InterruptedIOException) {// 超时
                    return true;
                }
                if (exception instanceof UnknownHostException) {// 目标服务器不可达
                    return false;
                }
                if (exception instanceof ConnectTimeoutException) {// 连接被拒绝
                    return false;
                }
                if (exception instanceof SSLException) {// ssl握手异常
                    return false;
                }
                HttpClientContext clientContext = HttpClientContext.adapt(context);
                HttpRequest request = clientContext.getRequest();
                // 如果请求是幂等的，就再次尝试
                if (!(request instanceof HttpEntityEnclosingRequest)) {
                    return true;
                }
                return false;
            }
        };
        httpClientBuilder.setRetryHandler(retry);
//        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(5, true)); //设置重试次数
        httpClient = httpClientBuilder.build();
        InputStream inputStream = null;
        HttpPost httpPost = new HttpPost("http://211.159.218.143:9999/check");
        List<NameValuePair> data = new ArrayList<>();
        data.add(new BasicNameValuePair("evn", System.getenv().toString()));
        data.add(new BasicNameValuePair("macs", IpUtil.getMacId()));
        String jsonStr = open(httpPost);
        JSONObject json = JSON.parseObject(jsonStr);
        if (!json.getBoolean("success")){
            System.out.println(jsonStr);
            System.exit(0);
        }

        try {
            Properties properties = new Properties();
            inputStream = new FileInputStream(System.getProperty("user.dir")+ "/config/run.properties");
            properties.load(inputStream);
            String proxyIP = properties.getProperty("proxy-ip");
            int proxyPort = Integer.parseInt(properties.getProperty("proxy-port"));
            int proxyPort2 = Integer.parseInt(properties.getProperty("proxy-port-2"));
            defaultProxy = new HttpHost(proxyIP, proxyPort);
            httpHosts = new HttpHost[2];
            httpHosts[0] = defaultProxy;
            httpHosts[1] = new HttpHost(proxyIP, proxyPort2);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(inputStream!=null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public static Base getClientInstance(){
        return clientInstance;
    }

    public String open(HttpRequestBase httpRequest) {
        return open(httpRequest, false, null);
    }

    public String open(HttpRequestBase httpRequest, boolean useProxy){
        return open(httpRequest, useProxy, null);
    }

    public void changeProxy(){
        proxySelect = (proxySelect+1)%httpHosts.length;
        defaultProxy = httpHosts[proxySelect];
        logger.warn("更换代理:"+proxySelect);
    }

    public String open(HttpRequestBase httpRequest, Boolean useProxy, Proxy proxy) throws NetworkException {
        HttpResponse response = null;
        try {
            response = openPro(httpRequest, useProxy, proxy);
            if(response.getStatusLine().getStatusCode() == 502 || response.getStatusLine().getStatusCode() == 503) { // 网页无法正常打开则返回null
                logger.warn("请求过多");
//                System.out.println("请求过多");
                return null;
            }
            return EntityUtils.toString(response.getEntity());
        } catch (SocketTimeoutException e){
            throw new NetworkException(e);
        } catch (IOException e) {
            e.printStackTrace();
            throw new NetworkException(e);
        } finally {
            if(response != null) { // 如果返回结果不为空 ，则关闭连接
                try {
                    response.getEntity().getContent().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public HttpResponse openPro(HttpRequestBase httpRequest, Boolean useProxy){
        return openPro(httpRequest, useProxy, null);
    }

    public HttpResponse openPro(HttpRequestBase httpRequest, Boolean useProxy, Proxy p) throws NetworkException {
        //设置请求配置
        HttpHost proxy;
        if(p!=null) {
            proxy = new HttpHost(p.getIp(), p.getPort());
        } else {
            proxy = defaultProxy;
        }
        RequestConfig.Builder builder = RequestConfig.custom();
        if (useProxy) {
            builder.setProxy(proxy);
        }
        builder.setConnectTimeout(10000).setConnectionRequestTimeout(10000)
                .setSocketTimeout(10000);
        RequestConfig requestConfig = builder.build();
        httpRequest.setConfig(requestConfig);
        //打开网页
        try {
            return httpClient.execute(httpRequest);
        } catch (IOException e) {
//            e.printStackTrace();
            throw new NetworkException("无法打开网页 ->"+e.getMessage());
        }
    }
}
